package ch.myDungeons.io;

import ch.myDungeons.characters.NPC;
import ch.myDungeons.characters.Person;
import ch.myDungeons.characters.Player;
import ch.myDungeons.game.Map;
import ch.myDungeons.game.Inventory.BagSlot;
import ch.myDungeons.gameObjects.Armor;
import ch.myDungeons.gameObjects.Potion;
import ch.myDungeons.gameObjects.Weapon;
import ch.myDungeons.game.MyDungeon;


/**
 * A static class to generate persons from templates
 * @author Grii
 *
 */
public class PersonGenerator {
	
	/** All the data for the monster types
	 * 0 npcTypeNames <> 1 npcWeaponNames <> 2 npcBaseAttackBonus <> 3 npcBaseAttackDice <> 4 npcDamageResistance <> 5 npcExpAward <> 6 npcHealthMultiplier <> 7 npcManaMultiplier <> 8 spawnChance
	 */
	private static Object[][] monsterData;
	
	/** The total chance of all monster types */
	private static double totalChance;
	
	static{
		loadData();
	}
	
	/** Loads the data file for the persons */
	public static void loadData(){
		String[] monsters = IOStream.loadPersonDataFile();
		monsterData = new Object[monsters.length][9];
		totalChance = 0;
		for (int i = 0; i < monsters.length; i++) {
			monsters[i] = monsters[i].replaceAll(" <>", "<>");
			monsters[i] = monsters[i].replaceAll("<> ", "<>");
			String[] tmpMonsterData = monsters[i].split("<>");
			if (tmpMonsterData.length == 9) {
				monsterData[i][0] = tmpMonsterData[0];
				monsterData[i][1] = tmpMonsterData[1];
				monsterData[i][2] = Integer.parseInt(tmpMonsterData[2]);
				monsterData[i][3] = Integer.parseInt(tmpMonsterData[3]);
				monsterData[i][4] = Integer.parseInt(tmpMonsterData[4]);
				monsterData[i][5] = Integer.parseInt(tmpMonsterData[5]);
				monsterData[i][6] = Integer.parseInt(tmpMonsterData[6]);
				monsterData[i][7] = Integer.parseInt(tmpMonsterData[7]);
				monsterData[i][8] = Double.parseDouble(tmpMonsterData[8]);
			} else {
				monsterData[i][0] = "peasant";
				monsterData[i][1] = "filthy console";
				monsterData[i][2] = 1;
				monsterData[i][3] = 1;
				monsterData[i][4] = 1;
				monsterData[i][5] = 1;
				monsterData[i][6] = 1;
				monsterData[i][7] = 1;
				monsterData[i][8] = 1.0;				
			}
			totalChance += (Double)monsterData[i][8];
		}
	}
	
	/** Returns a random fully equipped enemy */
	public static NPC createEnemy(int level){
		Double enemyType = (Double)(Math.random()*totalChance);
		loop:
		for (int i = 0; i < monsterData.length; i++) {
			enemyType -= (Double)monsterData[i][8];
			if (enemyType <= 0) {
				enemyType = 0.0;
				enemyType += i;
				break loop;
			}
		}
		return internalNPCCreator(level, (int)Math.round(enemyType), false);
	}
	
	/** Returns a fully equipped enemy with fixed type */
	public static NPC createEnemy(int level, int enemyType){
		return internalNPCCreator(level, enemyType, false);
	}
	
	/** Returns a random fully equipped ally */
	public static NPC createAlly(int level){
		Double npcType = (Double)(Math.random()*totalChance);
		loop:
		for (int i = 0; i < monsterData.length; i++) {
			npcType -= (Double)monsterData[i][8];
			if (npcType <= 0) {
				npcType = 0.0;
				npcType += i;
				break loop;
			}
		}
		return internalNPCCreator(level, (int)Math.round(npcType), true);
	}
	
	/** Returns a fully equipped ally with fixed type */
	public static NPC createAlly(int level, int npcType){
		return internalNPCCreator(level, npcType, true);
	}
	
	private static NPC internalNPCCreator(int level, int npcType, boolean friendly){
		if (level < 1) {
			level = 1;
		}
		
		NPC enemy = new NPC((String)monsterData[npcType][0], level, friendly);
		enemy.setExpAward((Integer)monsterData[npcType][5]);
		enemy.setNaturalWeapon((String)monsterData[npcType][1]);
		enemy.setBaseAttackBonus((Integer)monsterData[npcType][2]);
		enemy.setBaseAttackDice((Integer)monsterData[npcType][3]);
		enemy.setNaturalDamageResistance((Integer)monsterData[npcType][4]);
		enemy.setMaxHP(level*(Integer)monsterData[npcType][6]);
		enemy.setMaxMP(level*(Integer)monsterData[npcType][7]);
		
		enemy.setCurrentHP(enemy.getMaxHP());
		enemy.setCurrentMP(enemy.getMaxMP());
		int awardRating = 5*level + (Integer)monsterData[npcType][5];
		
		if (Math.random()*100 - awardRating < 50) {
			BagSlot p = ItemGenerator.createPotion(1 + (int)(awardRating*Math.random()/5));
			enemy.getInventory().addItem(p);
		}
		if (Math.random()*100 - awardRating < 30) {
			Armor a = ItemGenerator.createArmorFromRating(awardRating);
			enemy.getInventory().addItem(a);
		}
		if (Math.random()*100 - awardRating < 30) {
			Weapon w = ItemGenerator.createWeaponFromRating(awardRating);
			enemy.getInventory().addItem(w);
		}
		
		return enemy;
	}
	
	
	public static NPC createCowBoss(int level){
		if (level < 1) {
			level = 1;
		}
		NPC enemy = createPersonFromName("cow-man", level, false);
		
		BagSlot p = new BagSlot(new Potion.HealthPotion(""), 5);
		p.getItem().name = "milk";
		((Potion.HealthPotion)p.getItem()).healthRestore = 100;
		enemy.getInventory().addItem(p);
		
		Armor a = (Armor) ItemGenerator.createItemFromName("robe of the mighty moo");
		enemy.getInventory().addItem(a);
		
		Weapon w = (Weapon) ItemGenerator.createItemFromName("staff of the tremendous muh");
		enemy.getInventory().addItem(w);		
		return enemy;
	}
	
	/** Returns an item with the name specified */
	public static NPC createPersonFromName(String personName, int level, boolean friendly){
		NPC person = null;
		boolean foundPerson = false;
		for (int i = 0; i < monsterData.length && !foundPerson; i++) {
			if (((String)monsterData[i][0]).equals(personName)) {
				person = internalNPCCreator(level, i, friendly);
				foundPerson = true;
			}
		}
		return person;
	}
	
	/** Loads a person from a string
	 * @deprecated */
	@Deprecated
	public static Person createPersonFromSavedString(String personString, Map map){
		Person loadedPerson;
		String[] dataStrings = personString.split("<PERSONINFO>");
		
		String name = dataStrings[0];
		int level = Integer.parseInt(dataStrings[1]);
		int maxHP = Integer.parseInt(dataStrings[2]);
		int maxMP = Integer.parseInt(dataStrings[3]);
		int currentHP = Integer.parseInt(dataStrings[4]);
		int currentMP = Integer.parseInt(dataStrings[5]);
		boolean friendly = dataStrings[6].equals("true");
		String naturalWeapon = dataStrings[7];
		int baseAttackBonus = Integer.parseInt(dataStrings[8]);
		int baseAttackDice = Integer.parseInt(dataStrings[9]);
		int naturalDamageResistance = Integer.parseInt(dataStrings[10]);
		int activeWeaponIndex = Integer.parseInt(dataStrings[11]);
		int activeArmorIndex = Integer.parseInt(dataStrings[12]);
		BagSlot[] items = ItemGenerator.createItemsFormString(dataStrings[13]);
		int xpPoints = Integer.parseInt(dataStrings[14]);
		boolean isPlayer = dataStrings[15].equals("true");
		
		if(isPlayer){
			loadedPerson = new Player(name);
			loadedPerson.setFriendly(true);
			loadedPerson.setLevel(level);
			((Player)loadedPerson).setXpPoints(xpPoints);
		} else {
			loadedPerson = new NPC(name, level, friendly);
			((NPC)loadedPerson).setExpAward(xpPoints);
		}
		
		loadedPerson.setMaxHP(maxHP);
		loadedPerson.setMaxMP(maxMP);
		loadedPerson.setCurrentHP(currentHP);
		loadedPerson.setCurrentMP(currentMP);
		loadedPerson.setNaturalWeapon(naturalWeapon);
		loadedPerson.setBaseAttackBonus(baseAttackBonus);
		loadedPerson.setBaseAttackDice(baseAttackDice);
		loadedPerson.setNaturalDamageResistance(naturalDamageResistance);
		loadedPerson.setConsole(MyDungeon.game.gameFrame.getConsole());
		for (int i = 0; i < items.length; i++) {
			loadedPerson.getInventory().addItem(items[i]);
		}
		
		if (activeArmorIndex >= 0 && activeArmorIndex < loadedPerson.getInventory().size()) {
			loadedPerson.setActiveArmor((Armor)loadedPerson.getInventory().get(activeArmorIndex).getItem());
		} else {
			loadedPerson.setActiveArmor(null);
		}
		
		if (activeWeaponIndex >= 0 && activeWeaponIndex < loadedPerson.getInventory().size()) {
			loadedPerson.setActiveWeapon((Weapon)loadedPerson.getInventory().get(activeWeaponIndex).getItem());
		} else {
			loadedPerson.setActiveWeapon(null);
		}
		
		loadedPerson.setMap(map);
		return loadedPerson;
	}
}




